/**
 * @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 */
'use strict';

const log = require('lighthouse-logger');
const constants = require('../../config/constants.js');
const pageFunctions = require('../../lib/page-functions.js');
const i18n = require('../../lib/i18n/i18n.js');

const UIStrings = {
  /**
   * @description Warning that the host device where Lighthouse is running appears to have a slower
   * CPU than the expected Lighthouse baseline.
   */
  warningSlowHostCpu: 'The tested device appears to have a slower CPU than  ' +
  'Lighthouse expects. This can negatively affect your performance score. Learn more about ' +
  '[calibrating an appropriate CPU slowdown multiplier](https://github.com/GoogleChrome/lighthouse/blob/master/docs/throttling.md#cpu-throttling).',
};

/**
 * We want to warn when the CPU seemed to be at least ~2x weaker than our regular target device.
 * We're starting with a more conservative value that will increase over time to our true target threshold.
 * @see https://github.com/GoogleChrome/lighthouse/blob/ccbc8002fd058770d14e372a8301cc4f7d256414/docs/throttling.md#calibrating-multipliers
 */
const SLOW_CPU_BENCHMARK_INDEX_THRESHOLD = 1000;

const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);

/**
 * @param {LH.Gatherer.FRProtocolSession} session
 * @return {Promise<LH.Crdp.Browser.GetVersionResponse & {milestone: number}>}
 */
async function getBrowserVersion(session) {
  const status = {msg: 'Getting browser version', id: 'lh:gather:getVersion'};
  log.time(status, 'verbose');
  const version = await session.sendCommand('Browser.getVersion');
  const match = version.product.match(/\/(\d+)/); // eg 'Chrome/71.0.3577.0'
  const milestone = match ? parseInt(match[1]) : 0;
  log.timeEnd(status);
  return Object.assign(version, {milestone});
}

/**
 * Computes the benchmark index to get a rough estimate of device class.
 * @param {LH.Gatherer.FRTransitionalDriver['executionContext']} executionContext
 * @return {Promise<number>}
 */
async function getBenchmarkIndex(executionContext) {
  const status = {msg: 'Benchmarking machine', id: 'lh:gather:getBenchmarkIndex'};
  log.time(status);
  const indexVal = await executionContext.evaluate(pageFunctions.computeBenchmarkIndex, {
    args: [],
  });
  log.timeEnd(status);
  return indexVal;
}

/**
 * Returns a warning if the host device appeared to be underpowered according to BenchmarkIndex.
 *
 * @param {{settings: LH.Config.Settings; baseArtifacts: Pick<LH.Artifacts, 'BenchmarkIndex'>}} context
 * @return {LH.IcuMessage | undefined}
 */
function getSlowHostCpuWarning(context) {
  const {settings, baseArtifacts} = context;
  const {throttling, throttlingMethod} = settings;
  const defaultThrottling = constants.defaultSettings.throttling;

  // We only want to warn when the user can take an action to fix it.
  // Eventually, this should expand to cover DevTools.
  if (settings.channel !== 'cli') return;

  // Only warn if they are using the default throttling settings.
  const isThrottledMethod = throttlingMethod === 'simulate' || throttlingMethod === 'devtools';
  const isDefaultMultiplier =
    throttling.cpuSlowdownMultiplier === defaultThrottling.cpuSlowdownMultiplier;
  if (!isThrottledMethod || !isDefaultMultiplier) return;

  // Only warn if the device didn't meet the threshold.
  // See https://github.com/GoogleChrome/lighthouse/blob/master/docs/throttling.md#cpu-throttling
  if (baseArtifacts.BenchmarkIndex > SLOW_CPU_BENCHMARK_INDEX_THRESHOLD) return;

  return str_(UIStrings.warningSlowHostCpu);
}

/**
 * @param {{settings: LH.Config.Settings, baseArtifacts: Pick<LH.Artifacts, 'BenchmarkIndex'>}} context
 * @return {Array<LH.IcuMessage>}
 */
function getEnvironmentWarnings(context) {
  return [
    getSlowHostCpuWarning(context),
  ].filter(/** @return {s is LH.IcuMessage} */ s => !!s);
}

module.exports = {
  UIStrings,
  getBrowserVersion,
  getBenchmarkIndex,
  getSlowHostCpuWarning,
  getEnvironmentWarnings,
};
